#include "stdafx.h"
#include <boost/test/auto_unit_test.hpp>
#include <boost/bind.hpp>
#include <cstring>
#include "bmock.hpp"
#include "bmock_control_tools_mock.hpp"
#include "bmock_util.hpp"

static void f(const char *const str)
{
	STATIC_MOCK_VOID(1, (IN(str)));
}

static void k(int x)
{
	STATIC_MOCK_VOID(1, (IN(x)));
}

static void g(char *const str)
{
	STATIC_MOCK_VOID(1, (OUT(str)));
}

static const char s_str[] = "qwertyuiop[]";

struct callback {
	callback() {
		std::fill_n(buf,sizeof(buf),0);
	}

	static const size_t L = sizeof(s_str);
	char buf[L];
	int x;
};

const size_t callback::L;

BMOCK_TEST(callback,test_OK) {
	BOOST_CHECK_NO_THROW(BMOCK_EXPECT(f(s_str)));
	BOOST_CHECK_NO_THROW(BMOCK_EXPECT_CALLBACK(boost::bind(g,buf)));
	BOOST_CHECK_NO_THROW(BMOCK_EXPECT(g((char *)s_str)));
	BMOCK_REPLAY;
	BOOST_CHECK_NO_THROW(f(s_str));
	BOOST_CHECK_EQUAL(L,bmock::mismatch_at(buf,buf+L,s_str));
	BMOCK_VERIFY;
}

BOOST_AUTO_TEST_CASE(testCallback_misplaced) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+6);

	__BMOCK_EXPECT_C(c,t->error(bmock::message(bmock::INVALID_EXPECT_CALLBACK),loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		BMOCK_EXPECT_CALLBACK(boost::bind(g,(char *)NULL));
		__BMOCK_REPLAY_C(c1);
		__BMOCK_VERIFY_C(c1);
	}
	__BMOCK_VERIFY_C(c);
}

BMOCK_TEST(callback,test_invoke_callback_from_stub) {
	BOOST_CHECK_NO_THROW(BMOCK_STUB(f(s_str)));
	BOOST_CHECK_NO_THROW(BMOCK_EXPECT_CALLBACK(boost::bind(g,buf)));
	BOOST_CHECK_NO_THROW(BMOCK_EXPECT(g((char *)s_str)));
	BMOCK_REPLAY;
	BOOST_CHECK_NO_THROW(f(s_str));
	BOOST_CHECK_EQUAL(L,bmock::mismatch_at(buf,buf+L,s_str));
	BMOCK_VERIFY;
}

BMOCK_TEST(callback,test_stub_callback) {
	BOOST_CHECK_NO_THROW(BMOCK_EXPECT(f(s_str)));
	BOOST_CHECK_NO_THROW(BMOCK_EXPECT_CALLBACK(boost::bind(g,buf)));
	BOOST_CHECK_NO_THROW(BMOCK_STUB(g((char *)s_str)));
	BMOCK_REPLAY;
	BOOST_CHECK_NO_THROW(f(s_str));
	BOOST_CHECK_EQUAL(L,bmock::mismatch_at(buf,buf+L,s_str));
	BMOCK_VERIFY;
}

BMOCK_TEST(callback,test_callback_invoked_by_last_stub) {
	BOOST_CHECK_NO_THROW(BMOCK_EXPECT(g((char *)s_str)));
	BOOST_CHECK_NO_THROW(BMOCK_EXPECT(f(s_str)));
	BOOST_CHECK_NO_THROW(BMOCK_STUB(k(x)));
	BOOST_CHECK_NO_THROW(BMOCK_EXPECT_CALLBACK(boost::bind(g,buf)));
	BMOCK_REPLAY;
	BOOST_CHECK_NO_THROW(k(x));
	BOOST_CHECK_NO_THROW(f(s_str));
	BOOST_CHECK_EQUAL(L,bmock::mismatch_at(buf,buf+L,s_str));
	BMOCK_VERIFY;
}

BMOCK_TEST(callback,test_callback_invoked_by_last_expectation) {
	BOOST_CHECK_NO_THROW(BMOCK_STUB(k(x)));
	BOOST_CHECK_NO_THROW(BMOCK_EXPECT(f(s_str)));
	BOOST_CHECK_NO_THROW(BMOCK_EXPECT_CALLBACK(boost::bind(g,buf)));
	BOOST_CHECK_NO_THROW(BMOCK_EXPECT(g((char *)s_str)));
	BMOCK_REPLAY;
	BOOST_CHECK_NO_THROW(k(x));
	BOOST_CHECK_NO_THROW(f(s_str));
	BOOST_CHECK_EQUAL(L,bmock::mismatch_at(buf,buf+L,s_str));
	BMOCK_VERIFY;
}

